#include "teststdafx.h"
#include "stdafx.h"
#include <gtest/gtest.h>

#include "Business/Policy/SuperOpenBusiness.h"
#include "Utils/TimeoutNotifier.h"
#include "Utils/FastBlockQueue.h"
#include "Business/QueueContext.h"
#include "Repository/CancellationRepository.h"
#include "Repository/DealingRepository.h"
#include "Service/MarketStorage.h"
#include "Business/Customer.h"
#include "Business/Command.h"
#include "Business/ExchangeNotify.h"
#include "Business/RequestTimeout.h"

using namespace std;

class SuperOpenBusinessTest : public testing::Test
{
protected:

	virtual void SetUp()
	{
		HANDLE hQuit = ::CreateEvent(NULL,TRUE,FALSE,NULL);
		m_customer.reset(new Customer("","",""));
		m_customer->SetOrginalAmount(10000.00);
		m_requestQueue.reset(FastBlockQueue::Create(hQuit));
		m_businessQueue.reset(FastBlockQueue::Create(hQuit));
		m_uiQueue.reset(FastBlockQueue::Create(hQuit));
		m_highTimerQueue.reset(FastBlockQueue::Create(hQuit));
		m_waitTimerQueue.reset(FastBlockQueue::Create(hQuit));
		m_dealingRepository.reset(new DealingRepository());
		m_cancellationRepository.reset(new CancellationRepository());
		m_queueContext.reset(new QueueContext(*m_requestQueue,*m_businessQueue,*m_uiQueue,*m_highTimerQueue,*m_waitTimerQueue));
		m_timeoutNotifier.reset(new TimeoutNotifier());
		InitMarket();
		SuperOpenPrices prices(150,10,120,10,180,10);
		m_business.reset(new SuperOpenBusiness(*m_customer,SuperOpenArgument(0,true,prices,m_startTime,7),m_marketStorage,*m_queueContext,*m_dealingRepository,*m_cancellationRepository,*m_timeoutNotifier));

	}
	virtual void TearDown()
	{
	}
	void InitMarket()
	{
		Variety variety("rb1010",1,10);
		double lastPrice = 3000.00;
		Prices buyPrices;
		buyPrices[0] = Price(3010,10);
		Prices sellPrices;
		sellPrices[0] = Price(2990,5);
		double upperLimit = 4000.00;
		double lowerLimit = 2000.00;
		double preSettlementPrice  = 3100.00;
		Market market(0,variety,lastPrice,0,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice); 

		m_marketStorage.Save(market);
	}

	Market CreateMarket0()
	{
		Variety variety("UNDEFINED",-1,-1);
		double lastPrice = 3000.00;
		Prices buyPrices;
		buyPrices[0] = Price(3010,10);
		Prices sellPrices;
		sellPrices[0] = Price(2990,5);
		double upperLimit = 4000.00;
		double lowerLimit = 2000.00;
		double preSettlementPrice  = 3100.00;
		return Market(0,variety,lastPrice,0,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice); 
	}

	void ExpectSnapshot(char const* statusName, int quantity, double price)
	{
		EXPECT_EQ(1,m_queueContext->GetUIQueue().Size());
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetUIQueue().Pop(quitFlag);
		EXPECT_EQ(QueueItem::COMMAND,item.type);
		Command const& cmd = *(Command*)item.data;
		EXPECT_EQ(Command::UI_UPDATE_BUSINESS_INFO,cmd.type);
		SuperOpenBusinessSnapshot const& snapshot = *(SuperOpenBusinessSnapshot*)cmd.data;
		EXPECT_STREQ(statusName,snapshot.GetStatus());
		EXPECT_EQ(quantity,snapshot.GetQuantity());
		EXPECT_EQ(price,snapshot.GetPrice());
	}

	void ExpectOrder(int contract,Operation::TYPE operation,Direction::TYPE direction, int quantity,double price)
	{
		EXPECT_EQ(1,m_queueContext->GetRequestQueue().Size());
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
		EXPECT_EQ(QueueItem::ORDER,item.type);
		Dealing const& dealing = *(Dealing*)item.data;
		EXPECT_EQ(contract,dealing.GetContract());
		EXPECT_EQ(operation,dealing.GetOperation());
		EXPECT_EQ(direction,dealing.GetDirection());
		EXPECT_EQ(quantity,dealing.GetOrderQuantity());
		EXPECT_EQ(price,dealing.GetOrderPrice());
	}

	Dealing* OnOrdered()
	{
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
		Dealing* dealing = m_dealingRepository->Get(((Dealing*)item.data)->GetLocalId());
		dealing->OnOrdered(FT("%d",dealing->GetLocalId()));
		m_business->OnDealing(*dealing);
		return dealing;
	}

	Dealing* OnDealed(Dealing* dealing)
	{
		bool quitFlag = false;
		FT systemNo("%d",dealing->GetLocalId());
		Trade trade(*dealing,
			dealing->GetOrderPrice(),
			dealing->GetOrderQuantity(),
			systemNo);
		dealing->OnTrade(trade);
		m_business->OnTrade(trade);
		m_business->OnDealing(*dealing);
		return dealing;
	}


	MarketStorage m_marketStorage;
	auto_ptr<FastBlockQueue> m_requestQueue;
	auto_ptr<FastBlockQueue> m_businessQueue;
	auto_ptr<FastBlockQueue> m_uiQueue;
	auto_ptr<FastBlockQueue> m_highTimerQueue;
	auto_ptr<FastBlockQueue> m_waitTimerQueue;
	auto_ptr<Customer> m_customer;
	auto_ptr<SuperOpenBusiness> m_business;
	auto_ptr<DealingRepository> m_dealingRepository;
	auto_ptr<CancellationRepository> m_cancellationRepository;
	auto_ptr<QueueContext> m_queueContext;
	auto_ptr<TimeoutNotifier> m_timeoutNotifier;
	SYSTEMTIME m_startTime;

	void foo();
};
// 
// bool operator==(NoTradeTimeType const& l,NoTradeTimeType const& r)
// {
// 	return l.GetWaitTime() == r.GetWaitTime();
// }

bool operator==(SuperOpenArgument const& l,SuperOpenArgument const& r)
{
	return l.GetContract() == r.GetContract() &&
		l.GetDirection() == r.GetDirection() &&
		l.GetInterval() == r.GetInterval() &&
// 		l.GetNoTradeTime() == r.GetNoTradeTime() &&
		l.GetOffsetQuantity() == r.GetOffsetQuantity() &&
		l.GetOffsetPrice() == r.GetOffsetPrice() &&
		l.GetOpenPrice() == r.GetOpenPrice() &&
		l.GetOpenQuantity() == r.GetOpenQuantity() &&
		l.GetStopPrice() == r.GetStopPrice();
}

ostream& operator<<(ostream& os,SuperOpenArgument const& arg)
{
	os << arg.GetContract() << " ";
	os << arg.GetDirection() << " ";
	os << arg.GetInterval() << " ";
//	os << arg.GetNoTradeTime().GetName() << " " << arg.GetNoTradeTime().GetWaitTime() << " ";
	os << arg.GetOffsetQuantity() << " ";
	os << arg.GetOffsetPrice() << " ";
	os << arg.GetOpenPrice() << " ";
	os << arg.GetOpenQuantity() << " ";
	os << arg.GetStopPrice() << " ";
	return os;
}

TEST_F(SuperOpenBusinessTest,UpdateArgumentTest)/*
void SuperOpenBusinessTest::foo() /* */
{
	SuperOpenPrices prices(160,50,130,50,190,50);
	SuperOpenArgument expectedArgument(0,true,prices,m_startTime,10);
	
	Command cmd = {0};
	cmd.type = Command::UPDATE_ARGUMENT_COMMAND;
	SuperOpenArgument& arg = *(SuperOpenArgument*)cmd.data;
	arg = expectedArgument;
	m_business->OnCommand(cmd);

	EXPECT_EQ(expectedArgument,m_business->GetArgument());
}

TEST_F(SuperOpenBusinessTest,StartAndEditCommandTest)/*
void SuperOpenBusinessTest::foo() /* */
{
	Command cmd = {0};
	cmd.type = Command::EDIT_COMMAND;
	m_business->OnCommand(cmd);

	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());
	EXPECT_TRUE(m_business->IsEditable());

	cmd.type = Command::START_COMMAND;
	m_business->OnCommand(cmd);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
}

TEST_F(SuperOpenBusinessTest,NoTradeStatusTest)/*
void SuperOpenBusinessTest::foo() /* */
{
	Command cmd = {0};
	cmd.type = Command::START_COMMAND;
	m_business->OnCommand(cmd);

	EXPECT_EQ(1,m_waitTimerQueue->Size());
}

TEST_F(SuperOpenBusinessTest,OpenSentStatusTest)/*
void SuperOpenBusinessTest::foo() /* */
{
	Command cmd = {0};
	cmd.type = Command::START_COMMAND;
	m_business->OnCommand(cmd);
	ExpectSnapshot("start",0,0);

// 	m_business->OnExchangeStatus(ExchangeStatus::NO_TRADING);

// 	ExpectSnapshot("no order",0,0);
 	m_business->OnTimeout(RequestTimeout::CreateWaitable(m_business.get()));
	ExpectSnapshot("open sent",0,0);
	ExpectOrder(0,Operation::OPEN,Direction::BUY,10,150);
}

TEST_F(SuperOpenBusinessTest,EnoughOpenSentStatusTest)/*
void SuperOpenBusinessTest::foo() /* */
{
	Command cmd = {0};
	cmd.type = Command::START_COMMAND;
	m_business->OnCommand(cmd);
	ExpectSnapshot("start",0,0);

// 	m_business->OnExchangeStatus(ExchangeStatus::NO_TRADING);

// 	ExpectSnapshot("no order",0,0);
	m_business->OnTimeout(RequestTimeout::CreateWaitable(m_business.get()));
	ExpectSnapshot("open sent",0,0);
	ExpectOrder(0,Operation::OPEN,Direction::BUY,10,150);

	for (int i =0; i < 60; ++i)
	{
		m_business->OnTimeout(RequestTimeout::CreateHigh(m_business.get()));
		ExpectOrder(0,Operation::OPEN,Direction::BUY,10,150);
	}
 	m_business->OnTimeout(RequestTimeout::CreateHigh(m_business.get()));
	ExpectSnapshot("enough open sent",0,0);
}


TEST_F(SuperOpenBusinessTest,OpenOrderedStatusTest)/*
void SuperOpenBusinessTest::foo() /* */
{
	Command cmd = {0};
	cmd.type = Command::START_COMMAND;
	m_business->OnCommand(cmd);
	ExpectSnapshot("start",0,0);

// 	m_business->OnExchangeStatus(ExchangeStatus::NO_TRADING);

// 	ExpectSnapshot("no order",0,0);
	m_business->OnTimeout(RequestTimeout::CreateWaitable(m_business.get()));
	ExpectSnapshot("open sent",0,0);
	ExpectOrder(0,Operation::OPEN,Direction::BUY,10,150);

	for (int i =0; i < 59; ++i)
	{
		m_business->OnTimeout(RequestTimeout::CreateHigh(m_business.get()));
		ExpectOrder(0,Operation::OPEN,Direction::BUY,10,150);
	}
	m_business->OnTimeout(RequestTimeout::CreateHigh(m_business.get()));
	EXPECT_STREQ("open sent",m_business->GetSnapshot().GetStatus());
	m_business->OnTimeout(RequestTimeout::CreateHigh(m_business.get()));
	ExpectSnapshot("enough open sent",0,0);
	Dealing* openDealing = OnOrdered();
	ExpectSnapshot("open ordered",0,0);
	openDealing = OnDealed(openDealing);
	ExpectSnapshot("opened",10,150);
	m_business->OnTimeout(RequestTimeout::CreateBase(m_business.get()));
	ExpectSnapshot("auto offset",10,150);


}